#ifndef GRITC_SCENE_NODE_HPP
#define GRITC_SCENE_NODE_HPP

#include <gritc/meta/lazy.hpp>
#include <vector>

namespace gritc { namespace scene {

	template<class Traits> struct node
	{
		typedef typename Traits::tick_monad_type tick_monad_type;
		typedef typename Traits::draw_monad_type draw_monad_type;
		typedef typename Traits::pick_monad_type pick_monad_type;

		virtual ~node(){}

		tick_monad_type tick_monad_;
		draw_monad_type draw_monad_;
		pick_monad_type pick_monad_;

		tick_monad_type & tick() { return tick_monad_; }
		draw_monad_type & draw() { return draw_monad_; }
		pick_monad_type & pick() { return pick_monad_; }
	};

	template<class Node> struct node_group : Node
	{
		typedef std::vector<Node*> node_list;

		node_list nodes_;
		node_list & nodes(){ return nodes_; }
	};

	struct tick_node_group_
	{
		template<class C, class G> struct result { typedef gritc::meta::deref<C>::type & type; };
		template<class GCon, class Group> GCon & operator()(GCon & gcon, Group & group_) const
		{
			typedef Group::node_list L;
			L & l = group_.nodes();
			for(L::iterator i = l.begin(); i != l.end(); ++i)
				(*i)->tick()(gcon);
		}
	};
	gritc::meta::lazy<tick_node_group_> const tick_node_group = tick_node_group_();

	struct draw_node_group_
	{
		template<class C, class G> struct result { typedef gritc::meta::deref<C>::type & type; };
		template<class GCon, class Group> GCon & operator()(GCon & gcon, Group & group_) const
		{
			typedef Group::node_list L;
			L & l = group_.nodes();
			for(L::iterator i = l.begin(); i != l.end(); ++i)
				(*i)->draw()(frame_);
		}
	};
	gritc::meta::lazy<draw_node_group_> const draw_node_group = draw_node_group_();

	struct pick_node_group_
	{
		template<class T, class G> struct result { typedef gritc::meta::deref<T>::type type; };
		template<class Test, class Group> Test operator()(Test & test_, Group & group_) const
		{
			typedef Group::node_list L;
			L & l = group_.nodes();
			for(L::iterator i = l.begin(); i != l.end(); ++i)
				(*i)->pick()(test_);
		}
	};
	gritc::meta::lazy<pick_node_group_> const pick_node_group = pick_node_group_();

}}

#endif